package com.swak.job.manager.jobs;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.support.CronExpression;

import com.swak.Constants;
import com.swak.annotation.Context;
import com.swak.annotation.Flux;
import com.swak.annotation.Job;
import com.swak.job.JobFragment;
import com.swak.job.JobTask;
import com.swak.job.queue.QueueService;
import com.swak.job.storage.StorageService;
import com.swak.registry.URL;
import com.swak.utils.time.DateTimes;

/**
 * 内部任务：定义重试任务
 * 
 * 描述： 默认每次扫描 5分钟之前的任务；
 * 
 * @author DELL
 */
@Flux
@Job(id = "RetryJob", name = "失败任务重试", cronExpression = "0 0/5 * * * *", executeMethod = "execute", retryTimes = 0, order = true, context = Context.Order)
public class RetryJob {

	protected Logger logger = LoggerFactory.getLogger(RetryJob.class);

	@Autowired
	private StorageService storageService;
	@Autowired
	private QueueService queueService;

	private CronExpression cronSequenceGenerator;

	private long retryMillisSeconds = 5 * 60;

	/**
	 * 执行重试任务;
	 */
	public void execute(JobFragment fragment) {

		if (logger.isDebugEnabled()) {
			logger.debug(" RetryJob 开始执行任务 At {}.", DateTimes.getFormatNow(Constants.Second_Format));
		}

		// 调度器
		if (cronSequenceGenerator == null) {
			cronSequenceGenerator = CronExpression.parse(fragment.getJob().getCronExpression());
		}

		// 调度的间隔
		LocalDateTime todayDate = DateTimes.now();
		this.retryMillisSeconds = DateTimes.getMilliByTime(this.cronSequenceGenerator.next(todayDate))
				- DateTimes.getMilliByTime(todayDate);

		// 查询失败的任务
		LocalDateTime delayDate = DateTimes.minu(todayDate, retryMillisSeconds, ChronoUnit.MILLIS);
		List<JobTask> tasks = this.storageService.queryFailTasks(delayDate);

		if (logger.isDebugEnabled()) {
			logger.debug(" RetryJob 需要重试任务数： {} .", tasks.size());
		}

		for (JobTask task : tasks) {
			try {
				URL url = URL.valueOf(task.getExecuteUrl());
				String queue = this.queueService.parseExecuteQueue(url);
				this.queueService.publishQueue(queue, task);
			} catch (Throwable e) {
				logger.warn("RetryJob {} 执行失败", task.getJobName(), e);
			}
		}

		if (logger.isDebugEnabled()) {
			logger.debug(" RetryJob 执行结束.");
		}
	}
}